package com.triplelink.builder.query;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Queue;

import com.triplelink.annotations.Property;
import com.triplelink.builder.chain.InstanceBlockTOBuilder;
import com.triplelink.context.Connector;
import com.triplelink.exception.TripleLinkException;
import com.triplelink.to.steak.InstanceBlockTO;

public class SelectQueryBuilder
{
	private static final String THIS = "this";
	
	public static QueryTL build(String id, Class<?> entityClass, String abox, Connector connector)
	{
		QueryTL filter = QueryTL.create(connector);
		QueryTL recoverer = filter.shareResources();
		
		try
		{
			filter
			.append("SELECT DISTINCT ?s ?p ?o \n")
			.append("FROM <").append(abox).append("> \n")
			.append("WHERE \n")
			.append("{ \n")
			.plusTab()
			.appendTab()
			.append("{ \n")
			.plusTab()
			.appendTab()
			.append("SELECT * \n")
			.appendTab()
			.append("{ \n")
			.plusTab();
			
			recoverer.plusTab();
			
			build(id, entityClass, filter, recoverer);
	
			filter
			.decreaseTab()
			.appendTab()
			.append("} \n")
			.decreaseTab()
			.appendTab()
			.append("} \n")
			.append("\n")
			.append(recoverer.getSb())
			.decreaseTab()
			.appendTab()
			.append("} \n");
			
			return filter;
		}
		catch (IllegalArgumentException e)
		{
			throw new TripleLinkException(e);
		}
		catch (IllegalAccessException e)
		{
			throw new TripleLinkException(e);
		}
	}
	
	private static void build(String id, Class<?> entityClass, QueryTL filter, QueryTL recoverer) throws IllegalArgumentException, IllegalAccessException
	{
		Queue<InstanceBlockTO> queue = new LinkedList<InstanceBlockTO>();
		
		InstanceBlockTO rootInstanceBlockTO = InstanceBlockTOBuilder.build(entityClass, THIS, filter);
		
		queue.offer(rootInstanceBlockTO);
		
		buildFilterId(id, filter);
		buildUniosBlock(queue, filter, recoverer);
	}
	
	private static void buildFilterId(String id, QueryTL filter) throws IllegalArgumentException, IllegalAccessException
	{
		filter
		.appendTab()
		.append("VALUES ?").append(THIS).append(" \n")
		.appendTab()
		.append("{ \n")
		.plusTab()
		.appendTab()
		.appendUri(id).append("\n ")
		.decreaseTab()
		.appendTab()
		.append("} \n");
	}
	
	private static void buildUniosBlock(Queue<InstanceBlockTO> queue, QueryTL filter, QueryTL recoverer) throws IllegalArgumentException, IllegalAccessException
	{
		while (!queue.isEmpty())
		{
			InstanceBlockTO itemBlock = queue.remove();
			
			beginRecoverer(itemBlock, recoverer);
			
			Class<?> currentClass = itemBlock.getEntityClass();
			
			while (currentClass != null)
			{
				for (Field field : currentClass.getDeclaredFields())
					putValue(field, itemBlock, queue, filter, recoverer);
				
				currentClass = currentClass.getSuperclass();
			}
			
			endRecoverer(itemBlock, recoverer);
		}
	}
	
	private static void beginRecoverer(InstanceBlockTO itemBlock, QueryTL recoverer)
	{
		recoverer
		.appendTab()
		.append("{ \n")
		.plusTab()
		.appendTab()
		.append("?").append(itemBlock.getDisvoredLabelId()).append(" ?p ?o . \n")
		.appendTab()
		.append("BIND((?").append(itemBlock.getDisvoredLabelId()).append(") as ?s) \n")
		.appendTab()
		.append("VALUES ?p \n")
		.appendTab()
		.append("{ \n")
		.plusTab();
	}
	
	private static void endRecoverer(InstanceBlockTO itemBlock, QueryTL recoverer)
	{
		recoverer
		.decreaseTab()
		.appendTab()
		.append("} \n")
		.decreaseTab()
		.appendTab()
		.append("} \n");
	}
	
	private static void putValue(Field field, InstanceBlockTO item, Queue<InstanceBlockTO> queue, QueryTL filter, QueryTL recoverer) throws IllegalArgumentException, IllegalAccessException
	{
		field.setAccessible(true);
		
		Property property = field.getAnnotation(Property.class);
		
		if (property != null)
		{
			
			recoverer
			.appendTab().append(" <").append(property.uri()).append("> \n");
		}
		
	}
}